﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using AGPR.Locadora.Data;
using AGPR.Locadora.Utils;

namespace AGPR.Locadora.Model
{
    /// <summary>
    /// Classe de Produto
    /// </summary>
    public class Produto
    {
        private static ActiveRecord db = ActiveRecord.Instancia;

        #region Atributos

        /// <summary>
        /// Nome da Tabela de Produto no Banco de Dados
        /// </summary>
        public const string TABELA = "produto";

        /// <summary>
        /// Nome da View de Produto no Banco de Dados
        /// </summary>
        public const string VIEW = "vw_produto";

        /// <summary>
        /// Código do Produto
        /// </summary>
        [Display(Name = "Código do Produto")]
        public int id { get; set; }

        /// <summary>
        /// Código do Gênero
        /// </summary>
        [Required]
        [Display(Name = "Gênero")]
        public int id_genero { get; set; }

        /// <summary>
        /// Gênero
        /// </summary>
        public Genero genero { get; set; }

        /// <summary>
        /// Código da Mídia
        /// </summary>
        [Required]
        [Display(Name = "Mídia")]
        public int id_midia { get; set; }

        /// <summary>
        /// Mídia
        /// </summary>
        public Midia midia { get; set; }

        /// <summary>
        /// Nome do Produto
        /// </summary>
        [Required]
        [Display(Name = "Nome")]
        public string nome { get; set; }

        /// <summary>
        /// Descrição do Produto
        /// </summary>
        [Display(Name = "Descrição")]
        public string descricao { get; set; }

        /// <summary>
        /// Elenco do Filme
        /// </summary>        
        [Display(Name = "Elenco")]
        public string elenco { get; set; }

        /// <summary>
        /// Diretor do Filme
        /// </summary>
        [Display(Name = "Diretor")]
        public string diretor { get; set; }

        /// <summary>
        /// Quantidade em Estoque do Produto
        /// </summary>
        [Required]
        [Display(Name = "Qtd. Estoque")]
        public int qtd_estoque { get; set; }

        /// <summary>
        /// Valor do Produto
        /// </summary>
        [Display(Name = "Valor")]
        public decimal valor { get; set; }

        /// <summary>
        /// Valor do Produto Formatado
        /// </summary>
        [Display(Name = "Valor em Reais")]
        public string valorReais
        {
            get
            {
                return Format.formatarDinheiro(this.valor);
            }
            set
            {
                this.valor = Format.limparDecimal(value);
            }
        }

        /// <summary>
        /// Produto Ativo
        /// </summary>
        [Display(Name = "Ativo")]
        public bool ativo { get; set; }

        /// <summary>
        /// Status que vem de um checkbox
        /// </summary>
        public string ativoCheckBox
        {
            get
            {
                return Convert.ToString(this.ativo);
            }
            set
            {
                this.ativo = Format.toBoolean(value);
            }
        }

        /// <summary>
        /// Data de Lançamento
        /// </summary>
        [Display(Name = "Data de Lançamento")]
        public string data_lancamento { get; set; }

        /// <summary>
        /// Retorna o Ano de Lançamento baseado na Data de Lançamento
        /// </summary>
        public string ano
        {
            get
            {
                if (data_lancamento != null)
                {
                    return this.data_lancamento.Split('/')[2];
                }

                return null;
            }
        }

        /// <summary>
        /// Data de Cadastro
        /// </summary>
        [Display(Name = "Data de Cadastro")]
        public DateTime data_cadastro { get; set; }

        /// <summary>
        /// Imagem ilustrativa do Produto
        /// </summary>
        [Display(Name = "Imagem do Produto")]
        public string imagem { get; set; }

        /// <summary>
        /// Visualização da Imagem
        /// </summary>
        public string img
        {
            get
            {
                return this.imagem != null ? this.imagem : "~/Static/img/produto.png";
            }
        }

        #endregion

        #region getNextID

        /// <summary>
        /// Retorna o Proximo ID do Produto
        /// </summary>
        /// <returns>ID</returns>
        private int getNextID()
        {
            return db.max("id_produto", TABELA) + 1;
        }

        #endregion

        #region Create

        /// <summary>
        /// Retorna uma instância de Produto populada
        /// </summary>
        /// <param name="dados">Dados</param>
        /// <returns>Produto</returns>
        public static Produto Create(dynamic dados = null)
        {
            Produto produto = new Produto();

            if (dados != null)
            {
                produto.id = Convert.ToInt32(dados["id_produto"]);
                produto.id_genero = Convert.ToInt32(dados["id_genero"]);
                produto.id_midia = Convert.ToInt32(dados["id_midia"]);
                produto.genero = Genero.Get(produto.id_genero);
                produto.midia = Midia.Get(produto.id_midia);
                produto.nome = dados["nome"];
                produto.descricao = dados["descricao"];
                produto.elenco = dados["elenco"];
                produto.diretor = dados["diretor"];
                produto.imagem = dados["imagem"];
                produto.valor = Convert.ToDecimal(dados["valor"]);
                produto.qtd_estoque = Convert.ToInt32(dados["qtd_estoque"]);
                produto.data_lancamento = dados["data_lancamento"];
                produto.data_cadastro = Convert.ToDateTime(dados["data_cadastro"]);
                produto.ativo = Convert.ToBoolean(dados["ativo"]);
            }
            
            return produto;
        }

        #endregion

        #region Cadastrar

        /// <summary>
        /// Cadastra o Produto na Base de Dados
        /// </summary>
        /// <returns>Produto</returns>
        public Produto Cadastrar()
        {
            this.id = this.id > 0 ? this.id : this.getNextID();

            db.insert(TABELA, new Dictionary<string, dynamic>
            {
                {"id_produto", this.id},
                {"id_genero", this.id_genero},
                {"id_midia", this.id_midia},
                {"nome", this.nome},
                {"descricao", this.descricao},
                {"elenco", this.elenco},
                {"diretor", this.diretor},
                {"valor", this.valor},
                {"qtd_estoque", this.qtd_estoque},
                {"imagem", this.imagem},
                {"data_lancamento", this.data_lancamento},
                {"ativo", this.ativo}
            });

            return this;
        }

        #endregion

        #region Alterar

        /// <summary>
        /// Altera o Produto na base de dados
        /// </summary>
        /// <returns>Produto</returns>
        public Produto Alterar()
        {
            if (this.id > 0)
            {
                db.where("id_produto", this.id);
                db.update(TABELA, new Dictionary<string, dynamic>
                {
                    {"id_genero", this.id_genero},
                    {"id_midia", this.id_midia},
                    {"nome", this.nome},
                    {"descricao", this.descricao},
                    {"elenco", this.elenco},
                    {"diretor", this.diretor},
                    {"valor", this.valor},
                    {"qtd_estoque", this.qtd_estoque},
                    {"imagem", this.imagem},
                    {"data_lancamento", this.data_lancamento},
                    {"ativo", this.ativo}
                });
            }

            return this;
        }

        #endregion

        #region Excluir

        /// <summary>
        /// Exclui um Produto da base de dados
        /// </summary>
        /// <returns>Produto</returns>
        public Produto Excluir()
        {
            if (this.id > 0)
            {
                // Só excluo se não tiver nenhuma locação
                if (this.TotalLocacoes() == 0)
                {
                    db.where("id_produto", this.id).delete(TABELA);
                }
            }

            return this;
        }

        #endregion

        #region Get

        /// <summary>
        /// Retorna um Produto pelo ID
        /// </summary>
        /// <param name="id">ID do Produto</param>
        /// <returns>Produto</returns>
        public static Produto Get(dynamic id)
        {
            var item = db.where("id_produto", id).selectOne(VIEW);

            return item != null ? Produto.Create(item) : null;
        }

        /// <summary>
        /// Retorna uma lista de todos Produtos
        /// </summary>
        /// <returns>Lista de Produto</returns>
        public static List<Produto> GetAll(int offset = 0)
        {
            List<Produto> itens = new List<Produto>();

            db.limit(offset, Config.PageLimit).order_by("nome");

            foreach (var item in db.select(VIEW))
            {
                itens.Add(Produto.Create(item));
            }

            return itens;
        }

        #endregion

        #region Pesquisar

        /// <summary>
        /// Retorna os Produtos de acordo com a query
        /// </summary>
        /// <param name="query">query</param>
        /// <returns>Produtos</returns>
        public static List<Produto> Pesquisar(string query)
        {
            db.like("nome", query);

            return GetAll();
        }

        #endregion

        #region Total

        /// <summary>
        /// Retorna o Total de Produtos Cadastrados
        /// </summary>
        /// <returns>Total</returns>
        public static int Total()
        {
            return db.count(TABELA);
        }

        #endregion

        #region TotalLocacoes

        /// <summary>
        /// Retorna o Total de Locações deste Produto
        /// </summary>
        /// <returns>Total</returns>
        public int TotalLocacoes()
        {
            db.where("id_produto", this.id);
            return db.count(LocacaoProduto.TABELA);
        }

        #endregion
    }
}
